package com.zgis.module.bas.util;

import com.zgis.module.bas.constant.CxConsts;
import com.zgis.module.bas.constant.CxKeys;
import com.zgis.module.bas.constant.CxSymbol;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 修改记录:
 * 24-09-29     zhengchaojun             首次创建
 */

/**
 * 类描述：Map工具类
 */
public class CxMapUtil
{
    public static void main(String[] args)
    {
//        Map<String, Object> map = new HashMap<>();
//        map.put("name", "张三");
//        map.put("age", 18);
//        map.put("age2", 18.9);
//        map.put("age25", "5656");
//        String ret  = mapToStr(map);
//        String ret2 = mapToStr(map, "and");
//        System.out.println(ret);
//        System.out.println(ret2);


//        Map<String, Object> inputMap = new HashMap<>();
//        inputMap.put("name", "test");
//        inputMap.put("age", 18);
//        inputMap.put("age2", 18.3);
//        inputMap.put("size", "{\"name\":\"test\",\"age\":18,\"gender\":\"male\"}");
//        inputMap.put("gender", "male");
//        Map<String, Object> result = toDataColsTypes("employee", inputMap);
//        System.out.println("ppp-----"+result.toString());
//        System.out.println(formatMap(map));

        // 测试 getType 和 getTypeVal 方法
//        Map<String, Object> fldMap1 = new HashMap<>();
//        fldMap1.put("isnum", 1);
//        fldMap1.put("disptype", 0);
//        System.out.println("整数类型: " + getTypeVal(fldMap1)); // 输出: i
//
//        Map<String, Object> fldMap2 = new HashMap<>();
//        fldMap2.put("isnum", 2);
//        fldMap2.put("disptype", 0);
//        System.out.println("浮点类型: " + getTypeVal(fldMap2)); // 输出: r
//
//        Map<String, Object> fldMap3 = new HashMap<>();
//        fldMap3.put("isnum", 0);
//        fldMap3.put("disptype", 3);
//        System.out.println("日期类型: " + getTypeVal(fldMap3)); // 输出: d
//
//        Map<String, Object> fldMap4 = new HashMap<>();
//        fldMap4.put("isnum", 0);
//        fldMap4.put("disptype", 5);
//        System.out.println("日期时间类型: " + getTypeVal(fldMap4)); // 输出: t
//
//        Map<String, Object> fldMap5 = new HashMap<>();
//        fldMap5.put("isnum", 0);
//        fldMap5.put("disptype", 0);
//        System.out.println("字符串类型: " + getTypeVal(fldMap5)); // 输出: s
    }

    /**
     * 将map转换成字符串
     *
     * @param map 值如： {"name":"张三","age":18}
     * @return 结果如："name = '张三' , age=18"
     */
    public static String mapToStr(Map<String, Object> map, String... joinKey)
    {
        String        appendKey = Arrays.stream(joinKey).findFirst().orElse(CxSymbol.comma);
        StringBuilder result    = new StringBuilder();

        for (Map.Entry<String, Object> entry : map.entrySet())
        {
            if (result.length() > 0)
            {
                result.append(" " + appendKey + " ");
            }
            result.append(entry.getKey())
                    .append(" " + CxSymbol.equel + " ")
                    .append((entry.getValue() instanceof String && !entry.getKey().equals(CxKeys.geom)) ?
                            CxSymbol.single_quotation_mark + entry.getValue() + CxSymbol.single_quotation_mark : entry.getValue());
        }

        return result.toString();
    }

    /**
     * 格式化Map成字符串
     *
     * @param map 值如：  {"name":"张三","age":18}
     * @return 结果如：{"keys":"name,age", "values":"'张三',18"}
     */
    public static Map<String, Object> formatMap(Map<String, Object> map)
    {
        // 使用StringJoiner来构建字符串
        Map<String, Object> ret = new HashMap<String, Object>(2);

        StringJoiner keysJoiner   = new StringJoiner(CxSymbol.comma);
        StringJoiner valuesJoiner = new StringJoiner(CxSymbol.comma);

        // 遍历Map
        for (Map.Entry<String, Object> entry : map.entrySet())
        {
            keysJoiner.add(entry.getKey());
            // 添加单引号到非字符串的值周围
            if (entry.getValue() instanceof String && !entry.getKey().equals(CxKeys.geom))
            {
                valuesJoiner.add(CxSymbol.single_quotation_mark + entry.getValue() + CxSymbol.single_quotation_mark);
            }
            else
            {
                valuesJoiner.add(entry.getValue().toString());
            }
        }

        // 合并键和值的字符串
        ret.put(CxKeys.keys, keysJoiner.toString());
        ret.put(CxKeys.values, valuesJoiner.toString());
        return ret;
    }

    /**
     * 将输入的Map转换为特定格式的JSON对象。
     *
     * @param dataList 包含键值对的Map，键为列名，值为数据。        如：[{"name":"test","age":18,"gender":"male"}]
     * @param typesMap 列数据。                                 如：[{"name":"s","age":"i","gender":"s"}]
     * @return 返回一个Map，其结构适用于特定的JSON格式。            如：{"cols":"name,age,gender","types":"s,i,s","data":["test;18;male"]}
     */
    public static Map<String, Object> toDataColsTypes(List<Map<String, Object>> dataList, Map<String, String> typesMap)
    {
        Map<String, Object> ret = new HashMap<>();

        if (CxValueUtil.isEmpty(dataList))
        {
            return ret;
        }

        Map<String, Object> firstEmployee = dataList.get(0);
        String              cols          = String.join(CxSymbol.comma, firstEmployee.keySet());
        String types = firstEmployee.keySet().stream()
                .map(key ->
                {
                    String type = typesMap.get(key);
                    if(CxValueUtil.isEmpty(type))
                    {
                        Object value = firstEmployee.get(key);
                        if (value instanceof Integer || value instanceof Long)
                        {
                            return "i";
                        }
                        else if (value instanceof String)
                        {
                            return "s";
                        }
                        else if (value instanceof Double)
                        {
                            return "r";
                        }
                        else
                        {
                            // 默认为字符串类型
                            return "s";
                        }
                    }

                    return type;
                })
                .collect(Collectors.joining(CxSymbol.comma));

        // 构建data列表
        List<String> data = dataList.stream()
                .map(employee -> employee.keySet().stream()
                        .map(key ->
                        {
                            Object value = employee.get(key);
                            return !CxValueUtil.isEmpty(value) ? value.toString() : "";
                        })
                        .collect(Collectors.joining(CxSymbol.semicolon)))
                .collect(Collectors.toList());

        ret.put(CxKeys.data, data);
        ret.put(CxKeys.cols, cols);
        ret.put(CxKeys.types, types);
        return ret;
    }

    /**
     * 从Map对象中获取字段类型
     * 
     * @param fldMap 字段Map对象，包含 isnum 和 disptype 字段
     * @return 字段类型常量值
     */
    public static int getType(Map<String, Object> fldMap)
    {
        Integer isnum = (Integer) fldMap.get("isnum");
        Integer disptype = (Integer) fldMap.get("disptype");
        
        if (isnum == null)
        {
            isnum = 0;
        }
        if (disptype == null)
        {
            disptype = 0;
        }
        
        if (isnum == 1)
        {
            return CxConsts.DATA_LONG;
        }
        else if (isnum != 0)
        {
            return CxConsts.DATA_DOUBLE;
        }
        else
        {
            switch (disptype)
            {
                case 3:
                    return CxConsts.DATA_DATE;
                case 5:
                    return CxConsts.DATA_DATETIME;
                default:
                    return CxConsts.DATA_STRING;
            }
        }
    }

    /**
     * 从Map对象中获取字段类型值
     * 
     * @param fldMap 字段Map对象，包含 isnum 和 disptype 字段
     * @return 类型值字符串: i(整数), r(浮点), d(日期), t(日期时间), s(字符串)
     */
    public static String getTypeVal(Map<String, Object> fldMap)
    {
        int type = getType(fldMap);
        
        switch (type)
        {
            case CxConsts.DATA_LONG:
                return "i";
            case CxConsts.DATA_DOUBLE:
                return "r";
            case CxConsts.DATA_DATE:
                return "d";
            case CxConsts.DATA_DATETIME:
                return "t";
            default:
                return "s";
        }
    }
}
